home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
076-100
/
scopedisk81
/
planet
/
planet.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
15KB
|
598 lines
#include "planet.h"
main(argc,argv)
int argc;
char *argv[];
{
struct IntuiMessage *mess;
unsigned int mask,open_things();
int i,j,rad,ang;
long x,y,lx,ly,lz,vx,vy,vz,px,py,pz,v,pz2,r2;
float size,source,calp,lon,lat,light[3][3],trans[3][3];
char *c;
/* default values */
mapfile = (UBYTE *)"planet.map\0 ";
rad = 180;
dmax = 6;
size = 1.0;
/* setup identity matrices for light source and planet rotation */
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
if(i == j) light[i][j] = trans[i][j] = 1;
else light[i][j] = trans[i][j] = 0;
}
}
/* read command line argument values */
for(i = 1; i < argc; i++)
{
c = argv[i];
if(c[0] == '?') help();
else if(c[0] == '-')
{
switch(c[1])
{
case 'r' : if(argc > ++i) sscanf(argv[i],"%d",&rad);
break;
case 'h' : if(argc > ++i) sscanf(argv[i],"%d",&dmax);
break;
case 's' : if(argc > ++i) sscanf(argv[i],"%f",&size);
break;
case 'l' : if(argc > ++i) sscanf(argv[i],"%d",&ang);
rotate(c[2],ang,light);
break;
case 'p' : if(argc > ++i) sscanf(argv[i],"%d",&ang);
rotate(c[2],-ang,trans);
break;
case 'f' : CMFF = TRUE;
break;
default : printf("Error in arguments\n");
help();
break;
}
}
else sscanf(argv[i],"%s",mapfile);
}
/* compute light source vector */
lx = rad*light[0][2];
ly = rad*light[1][2];
lz = rad*light[2][2];
r2 = (long)(rad*rad);
/* compute light source size effect */
source = 2*atan((double)(size - 1.0))/PI;
mask = open_things();
/* loop on destination display coordinates */
for (y = 0L; y < 400L; ++y)
{
py = 200L - y;
ro = go = bo = 0;
for (x = 0L; x < 320L; ++x)
{
if(mess = (struct IntuiMessage *)GetMsg(w->UserPort))
CheckMess(mess,mask);
px = 25L*(x - 160L)/14L;
/* calculate for coordinates on planet surface only */
if((pz2 = r2 - (px*px + py*py)) > 0L)
{
pz = sqrt((double)pz2);
/* compute cosine of angle between normal and light source */
vx = px*trans[0][0] + py*trans[0][1] + pz*trans[0][2];
vy = px*trans[1][0] + py*trans[1][1] + pz*trans[1][2];
vz = px*trans[2][0] + py*trans[2][1] + pz*trans[2][2];
calp = (vx*lx + vy*ly + vz*lz)/(float)r2;
calp = (calp + source)/(1 + source);
/* dont bother with black part of planet */
if(calp > 0.0)
{
if(calp > 1.0) calp = 1.0;
/* compute longitude and latitude */
if((v = sqrt((double)(vy*vy + vz*vz))) == 0) v = 1;
lon = atan((double)vx/v);
if((v = sqrt((double)(vx*vx + vz*vz))) == 0) v = 1;
lat = atan((double)vy/v);
/* get color from planet map */
map(lon,lat);
PutPixel(x,y,calp);
}
}
}
}
close_things((unsigned int)ILBM);
mask ^= ILBM;
for(;;)
{
Wait(1L << w->UserPort->mp_SigBit);
if(mess = (struct IntuiMessage *)GetMsg(w->UserPort))
CheckMess(mess,mask);
}
} /* end main */
/* compute transformation and concatenate with previous transformation(s) */
rotate(axis,ang,m)
int axis,ang;
float (*m)[3];
{
int i,j,k;
float n[3][3],p[3][3];
/* setup tranformation matrix based on selected axis */
switch(axis)
{
case 'x': i = 0; j = 1; k = 2; break;
case 'y': i = 1; j = 2; k = 0; break;
case 'z': i = 2; j = 0; k = 1; break;
default : i = 0; j = 1; k = 2; break;
}
n[i][i] = 1.0;
n[j][j] = n[k][k] = cos((double)ang*PI/180);
n[i][j] = n[i][k] = n[j][i] = n[k][i] = 0.0;
n[k][j] = sin((double)ang*PI/180);
n[j][k] = -n[k][j];
/* concatenate with previously computed transformation matrix */
for(i = 0; i < 3; i++)
{
for(j = 0; j < 3; j++)
{
p[i][j] = 0.0;
for(k = 0; k < 3; k++) p[i][j] = p[i][j] + n[i][k]*m[k][j];
}
}
for(j = 0; j < 3; j++)
{
for(i = 0; i < 3; i++) m[i][j] = p[i][j];
}
} /* end rotate */
/* self explanitory */
help()
{
printf
("usage: planet [1] -r [2] -h [3] -s [4] -l[x,y,z 5] -p[x,y,z 6] -f [7]\n");
printf
(" 1: map file name (IFF); any ILBM [planet.map]\n");
printf
(" 2: radius of planet (pixels); 10 -> 180 [180]\n");
printf
(" 3: ham tweek factor (color gradients); 0 -> 45 [6]\n");
printf
(" 4: radius of light source (planet radii); 0.0 -> 10.0 [1.0]\n");
printf
(" 5: light source angle about axis (degrees); 0 -> 360 [x 0]\n");
printf
(" 6: planet rotation about axis (degrees); 0 -> 360 [x 0]\n");
printf
(" 7: color map from file; no argument\n");
exit(0);
} /* end help */
/* get color from map at specified longitude and latitude */
map(lon,lat)
float lon,lat;
{
int x,y,i,id;
x = (lon/PI + .5)*(Width-1);
y = (.5 - lat/PI)*(Height-1);
/* if map is HAM mode then full scan line must be processed */
if(ViewModes & HAM) {
rc = gc = bc = 0;
for(i = 0; i <= x; i++) {
id = ReadPixel(&maprp,(long)i,(long)y);
if((id & 48) == 32) rc = (id & 15);
else if((id & 48) == 48) gc = (id & 15);
else if((id & 48) == 16) bc = (id & 15);
else {
rc = rm[id];
gc = gm[id];
bc = bm[id];
}
}
}
/* else just read color value from map */
else {
id = ReadPixel(&maprp,(long)x,(long)y);
rc = rm[id];
gc = gm[id];
bc = bm[id];
}
} /* end map */
/* compute planet color value with shade applied */
PutPixel(x,y,ca)
long x,y;
float ca;
{
int r,g,b,dr,dg,db,val,d,diff,n;
/* multiply each color component with shade value */
r = ca*rc;
g = ca*gc;
b = ca*bc;
/* compute closest HAM color to desired color */
dr = ABS(r - ro);
dg = ABS(g - go);
db = ABS(b - bo);
if(dr > dg) {
if(dr > db) { ro = r; dr = 0; val = r + 32; }
else { bo = b; db = 0; val = b + 16; }
}
else {
if(dg > db) { go = g; dg = 0; val = g + 48; }
else { bo = b; db = 0; val = b + 16; }
}
diff = dr + dg + db;
/* check to see if any existing color comes closer */
for(n = nc; n >= 0; n--)
{
dr = ABS(r - rn[n]);
dg = ABS(g - gn[n]);
db = ABS(b - bn[n]);
d = dr + dg + db;
if(d <= diff) {
diff = d;
val = n;
ro = rn[n];
go = gn[n];
bo = bn[n];
}
}
/* if the difference between obtainable color and desired color exceeds
maximum difference (HAM tweek factor) then place desired color into
palatte (if there is room) and update color bar */
if((diff > dmax) && (nc < NCOL)) {
val = ++nc;
ro = rn[nc] = r;
go = gn[nc] = g;
bo = bn[nc] = b;
SetRGB4(vp,(long)nc,(long)r,(long)g,(long)b);
if(showtitle) DrawImage(trp,&square[15],0L,0L);
}
/* set color on displayed planet */
SetAPen(rp,(long)val);
WritePixel(rp,x,y);
} /* end PutPixel */
/* check to see what the user wants */
CheckMess(message,mask)
struct IntuiMessage *message;
unsigned int mask;
{
ULONG class;
unsigned int code,menunum,itemnum;
class = message->Class;
code = message->Code;
ReplyMsg(message);
if(class == MENUPICK)
{
menunum = MENUNUM(code);
itemnum = ITEMNUM(code);
switch(menunum)
{
case 0:
switch(itemnum)
{
case 0:
TitleShow();
break;
case 1:
close_things(mask);
exit(0);
}
}
if(showtitle) DrawImage(trp,&square[15],0L,0L);
}
} /* end CheckMess */
/* open everything */
unsigned int open_things()
{
unsigned int mask;
int i;
struct Library *OpenLibrary();
struct Screen *OpenScreen();
struct Window *OpenWindow();
struct ViewPort *ViewPortAddress();
mask = 0;
if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)))
{
printf("no graphics library!!!\n");
exit(1);
}
mask |= GRAPHICS;
if(!(IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library",0L)))
{
printf("no intuition library!!!\n");
close_things(mask);
exit(2);
}
mask |= INTUITION;
ns.DefaultTitle = mapfile;
if (!(s = OpenScreen(&ns)))
{
printf("could not open the screen\n");
close_things(mask);
exit(3);
}
mask |= SCREEN;
nw.Screen = s;
if (!(w = OpenWindow(&nw)))
{
printf("could not open the window\n");
close_things(mask);
exit(4);
}
mask |= WINDOW;
rp = w->RPort;
vp = ViewPortAddress(w);
SetMenuStrip(w,&ScrnMenu);
showtitle = TRUE;
TitleShow();
if (!ReadILBM(mapfile))
{
printf("could not get ILBM\n");
close_things(mask);
exit(5);
}
mask |= ILBM;
/* setup color bar */
for(i=0;i<16;i++) {
SetRGB4(vp,(long)i,(long)rn[i],(long)gn[i],(long)bn[i]);
square[i].LeftEdge = 158 + 8*i;
square[i].TopEdge = 0;
square[i].Width = 8;
square[i].Height = 10;
square[i].Depth = 0;
square[i].ImageData = NULL;
square[i].PlanePick = 0;
square[i].PlaneOnOff = i;
if(i != 0) square[i].NextImage = &square[i-1];
}
square[0].NextImage = NULL;
trp = s->BarLayer->rp;
return(mask);
} /* end open_things */
/* close things indicated by mask */
close_things(mask)
unsigned int mask;
{
int i;
if(mask & ILBM)
{
FreeMem(bufstart,(long)header.ckSize);
for(i=0;i<Depth;i++)
FreeMem(bmap.Planes[i],PlaneSize);
}
if(mask & WINDOW)
{
ClearMenuStrip(w);
CloseWindow(w);
}
if(mask & SCREEN) CloseScreen(s);
if(mask & GRAPHICS) CloseLibrary(GfxBase);
if(mask & INTUITION) CloseLibrary(IntuitionBase);
} /* end close_things */
/* toggle title bar */
TitleShow()
{
ClearMenuStrip(w);
if(showtitle)
{
showtitle = FALSE;
ScrnText1.IText = (UBYTE *)"Show Title Bar";
ShowTitle(s,FALSE);
}
else
{
showtitle = TRUE;
ScrnText1.IText = (UBYTE *)"Hide Title Bar";
ShowTitle(s,TRUE);
DrawImage(trp,&square[15],0L,0L);
}
SetMenuStrip(w,&ScrnMenu);
} /* end TitleShow */
/**************************************************************************
* *
* Routine name(s) : ReadILBM() *
* Author : D. John Hodgson (modified by Russell Leighton) *
* Environment : Aztec "C", default *
* *
* ReadILBM attempts to read an IFF file. If successful then contents *
* are stored in bitmap, bmap and a rastport, maprp is initialized. The *
* colormap is stored (the RGB components are kept separate) in the *
* array, mapcolors. *
* *
* LIMITATIONS : no masking, CATS/LISTS/PROPS. CAMG chunks supported. *
**************************************************************************/
int ReadILBM(fspec)
char *fspec; /* AmigaDOS filename */
{
struct FileHandle *fp,*Open();
UBYTE *sourcebuf,*destbuf,*AllocMem();
UBYTE colormap[MAXCOLORS][3];
short colorcount,plane,linelen,rowbytes,i,r,g,b;
long id;
char n;
if ((fp=Open(fspec,MODE_OLDFILE))==NULL) return(0);
SafeRead(fp,&header,(long)sizeof(header));
if (header.ckID!=ID_FORM) { Close(fp); return(0); }
SafeRead(fp,&id,(long)sizeof(id));
if (id!=ID_ILBM) { Close(fp); return(0); }
for (;;) {
SafeRead(fp,&header,(long)sizeof(header));
if (header.ckID==ID_BODY) break;
switch(header.ckID) {
case ID_BMHD: SafeRead(fp,&bmhd,(long)sizeof(bmhd));
break;
case ID_CMAP: SafeRead(fp,&colormap[0][0],(long)header.ckSize);
colorcount=header.ckSize/3;
break;
case ID_CAMG: SafeRead(fp,&ViewModes,(long)header.ckSize);
break;
default: Seek(fp,ROUNDODDUP(header.ckSize),OFFSET_CURRENT);
}
}
/* Read planes into RAM for ease if decompression */
sourcebuf=bufstart=AllocMem((long)header.ckSize,MEMF_PUBLIC | MEMF_CHIP);
if (sourcebuf==NULL) return(0);
SafeRead(fp,sourcebuf,(long)header.ckSize); Close(fp);
Width=bmhd.w;
Height=bmhd.h;
Depth=bmhd.nPlanes;
/* make some forced assumptions if CAMG chunk unavailable */
if (ViewModes == 0L) {
if (Width > MAXWIDTH) ViewModes |= HIRES;
if (Height > MAXHEIGHT) ViewModes |= LACE;
}
linelen=Width/8;
bmap.BytesPerRow = linelen;
bmap.Rows = Height;
bmap.Depth = (UBYTE)Depth;
PlaneSize = (long)(linelen*Height);
for(i=0;i<Depth;i++) { /* allocate space for bitmap */
bmap.Planes[i] = AllocMem(PlaneSize,MEMF_PUBLIC | MEMF_CHIP);
if(bmap.Planes[i] == NULL) return(0);
}
maprp.BitMap=&bmap;
while (colorcount--) {
rm[colorcount] = colormap[colorcount][0] >> 4L;
gm[colorcount] = colormap[colorcount][1] >> 4L;
bm[colorcount] = colormap[colorcount][2] >> 4L;
if(CMFF && (colorcount < 16)) {
rn[colorcount] = rm[colorcount];
gn[colorcount] = gm[colorcount];
bn[colorcount] = bm[colorcount];
}
}
if(CMFF) nc = NCOL;
for (i=0;i<Height;i++) /* process n lines/screen */
for (plane=0;plane<Depth;plane++) { /* process n planes/line */
destbuf=(UBYTE *)(bmap.Planes[plane])+linelen*i;
if (bmhd.compression==cmpByteRun1) { /* compressed screen? */
rowbytes=linelen;
while (rowbytes) { /* unpack until 1 scan-line complete */
n=*sourcebuf++; /* fetch block run marker */
/* uncompressed block? copy n bytes verbatim */
if (n>=0) {
movmem(sourcebuf,destbuf,(unsigned int)++n); rowbytes-=n;
destbuf+=n; sourcebuf+=n;
}
else { /* compressed block? expand n duplicate bytes */
n=-n+1; rowbytes-=n;
setmem(destbuf,(unsigned int)n,(unsigned int)*sourcebuf++);
destbuf+=n;
}
} /* finish unpacking line */
}
else { /* uncompressed? just copy */
movmem(sourcebuf,destbuf,(unsigned int)linelen);
sourcebuf+=linelen; destbuf+=linelen;
}
} /* finish interleaved planes, lines */
return(1);
} /* end ReadILBM */